﻿package Leophy.controls.Scrolls 
{
	import flash.display.InteractiveObject;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	import Leophy.controls.MotionClip.EasyMotionMovieClip;
	import Leophy.Interfaces.IControls.IScroll.IScorllEnable;
	import Leophy.Interfaces.IControls.IScroll.IScrollUI;
	
	/**
	 * ...
	 * @author TOPHY
	 */
	public class ScrollBase extends EasyMotionMovieClip implements IScrollUI
	{
		//======================================= 变量
		private var _hand:MovieClip;
		private var _bar:MovieClip;
		private var _step:Number = 5;
		private var _upBT:MovieClip;
		private var _downBT:MovieClip;
		private var _VorH:Boolean = true;
		private var _enabledMouseWheel:Boolean = true;
		private var _wheelType:String = "v";
		
		private var _scrollTarget:IScorllEnable;
		
		private var _value:Number = 0;
		private var _minValue:Number = 0;
		private var _maxValue:Number = 0;
		
		private var _startPressScrollButtonTime:uint = 0;
		
		
		/**
		 * 步进按键每多少时间速度加倍
		 */
		protected var _ScrollSpeedUpPS:uint = 1000;
		
		//======================================= 属性
		/**
		 * 鼠标滚轮作用方式:  v-垂直　h-水平　both-垂直与水平
		 */
		public function get WheelType():String {
			return _wheelType;
		}
		public function set WheelType(value:String) {
			value = value.toLowerCase();
			if (value.toLowerCase() != "v" && value.toLowerCase() != "h") {
				value = "both";
			}
			_wheelType = value;
		}
		/**
		 * 是否支持滚轮
		 */
		public function get MouseWheelEnable():Boolean {
			return _enabledMouseWheel;
		}
		public function set MouseWheelEnable(value:Boolean) {
			_enabledMouseWheel = value;
			var obji:InteractiveObject = _scrollTarget as InteractiveObject;
			if (_enabledMouseWheel) {
				if (obji != null && _enabledMouseWheel) {
					obji.removeEventListener(MouseEvent.MOUSE_WHEEL, mousewheelFun);
					obji.addEventListener(MouseEvent.MOUSE_WHEEL, mousewheelFun);
				}
			}else {
				if (obji != null && _enabledMouseWheel) {
					obji.removeEventListener(MouseEvent.MOUSE_WHEEL, mousewheelFun);
				}
			}
		}
		/**
		 * 指定步进（后退）按键
		 */
		public function get UPBT():MovieClip {
			return this._upBT;
		}
		public function set UPBT(value:MovieClip) {
			initstepupbt(value);
		}
		/**
		 * 指定步进（前进）按键
		 */
		public function get DOWNBT():MovieClip {
			return this._downBT;
		}
		public function set DOWNBT(value:MovieClip) {
			initstepdownbt(value);
		}
		/**
		 * 是(true)否(false)为垂直滚动界面
		 */
		public function get VorH():Boolean {
			return _VorH;
		}
		public function set VorH(value:Boolean) {
			_VorH = value;
		}
		/**
		 * 步进量
		 */
		public function get step():Number {
			return this._step;
		}
		public function set step(value:Number) {
			_step = value;
		}
		/**
		 * 把手
		 */
		public function get hand():MovieClip {
			return this._hand;
		}
		public function set hand(value:MovieClip) {
			inithand(value);
		}
		/**
		 * 滚动槽
		 */
		public function get bar():MovieClip {
			return this._bar;
		}
		public function set bar(value:MovieClip) {
			_bar = value;
		}
		//======================================= 函数
		public function ScrollBase() 
		{
			
		}
		/**
		 * 绑定滚动对象
		 * @param	obj　可以滚动的对象
		 */
		public function bindScrollObject(obj:IScorllEnable):void {
			_scrollTarget = obj;
			_scrollTarget.RegistResizeEvent(this);
			var obji:InteractiveObject = _scrollTarget as InteractiveObject;
			if (obji != null && _enabledMouseWheel) {
				obji.addEventListener(MouseEvent.MOUSE_WHEEL, mousewheelFun);
			}
			UpdataUI(obj.HValue,obj.MinScrollH, obj.MaxScrollH, obj.VValue,obj.MinScrollV, obj.MaxScrollV);
		}
		/**
		 * 更新滚动界面
		 * @param	HValue　水平位置
		 * @param	HMaxValue　水平最大位置
		 * @param	VValue　垂直位置
		 * @param	VMaxValue　垂直最大位置
		 */
		public function UpdataUI(HValue:Number,HMinValue:Number, HMaxValue:Number, VValue:Number,VMinValue:Number, VMaxValue:Number):void
		{
			//trace("updataUI:",arguments);
			
			if (_VorH) {
				if (VMaxValue < 0) VMaxValue=0;
				this._value = fixNumber(VValue);
				this._maxValue = fixNumber(VMaxValue);
				this._minValue = fixNumber(VMinValue);
			}else {
				if (HMaxValue < 0) HMaxValue=0;
				this._value = fixNumber(HValue);
				this._maxValue = fixNumber(HMaxValue);
				this._minValue = fixNumber(HMinValue);
			}
			updatauiCondition();
		}
		
		public function Enable(enable:Boolean):void
		{
			this.mouseEnabled = enable;
			this.mouseChildren = enable;
		}
		//======================================= private functions
		private function updatauiCondition() {
			if (_bar == null || _hand == null) return;
			var ttv:Number = 0;
			var handLength:Number = 0;
			var xory:Number = _value / (_maxValue - _minValue);
			var tempv:Number;
			if (VorH) {
				handLength = _bar.height - (_maxValue - _minValue) * 2-5;
				handLength = Math.max(20, handLength);
				handLength = Math.min(_bar.height, handLength);
				_hand.height = handLength;
				if (handLength == _bar.height) {
					_hand.visible = false;
				}else {
					_hand.visible = true;
				}
				_hand.y = _bar.y + (_bar.height - _hand.height) * xory;
				tempv = Math.min(_bar.y + _bar.height - _hand.height, _hand.y);
				if (tempv != _hand.y) {
					_hand.y = tempv;
					handEnterFrameFun(null);
				}
				
			}else {
				
				handLength = _bar.width - (_maxValue - _minValue) * 2 - 5;
				handLength = Math.max(20, handLength);
				handLength = Math.min(_bar.width, handLength);
				_hand.width = handLength;
				if (handLength == _bar.width) {
					_hand.visible = false;
				}else {
					_hand.visible = true;
				}
				_hand.x = _bar.x + (_bar.width - _hand.width) * xory;
				
				tempv = Math.min(_bar.x + _bar.width - _hand.width, _hand.x);
				if (tempv != _hand.x) {
					_hand.x = tempv;
					handEnterFrameFun(null);
				}
				
			}
		}
		private function initstepupbt(value:MovieClip) {
			if (value != null) {
				if (this._upBT != null) {
					this._upBT.removeEventListener(MouseEvent.MOUSE_DOWN, pressUPBT);
					this._upBT.removeEventListener(MouseEvent.MOUSE_UP, upUPBT);
					if (stage != null) {
						stage.removeEventListener(MouseEvent.MOUSE_UP, upUPBT);
					}
				}
				this._upBT = value;
				this._upBT.buttonMode = true;
				this._upBT.addEventListener(MouseEvent.MOUSE_DOWN, pressUPBT);
				this._upBT.addEventListener(MouseEvent.MOUSE_UP, upUPBT);
				if (stage != null) {
					stage.addEventListener(MouseEvent.MOUSE_UP, upUPBT);
				}
			}
		}
		private function initstepdownbt(value:MovieClip) {
			if (value != null) {
				if (this._downBT != null) {
					this._downBT.removeEventListener(MouseEvent.MOUSE_DOWN, pressDOWNBT);
					this._downBT.removeEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
					if (stage != null) {
						stage.removeEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
					}
				}
				this._downBT = value;
				this._downBT.buttonMode = true;
				this._downBT.addEventListener(MouseEvent.MOUSE_DOWN, pressDOWNBT);
				this._downBT.addEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
				if (stage != null) {
					stage.addEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
				}
			}
		}
		private function inithand(value:MovieClip) {
			
			if (value != null) {
				if (this._hand != null) {
					this._hand.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownFun);
					this._hand.removeEventListener(MouseEvent.MOUSE_UP, mouseUpFun);
					if (stage != null) {
						stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpFun);
					}
				}
				this._hand = value;
				this._hand.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownFun);
				this._hand.addEventListener(MouseEvent.MOUSE_UP, mouseUpFun);
				if (stage != null) {
					stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpFun);
				}
				_hand.buttonMode = true;
			}
		}
		//========================================= events
		// mouse wheel
		private function mousewheelFun(ev:MouseEvent) {
			var t:Number = (_maxValue - _minValue) / 20;
			if (ev.delta > 0) {
				t = -t;
			}
			t = _value + t;
			
			if (_VorH) {
				if(_wheelType=="both" || _wheelType=="v"){
					_value = Math.min(_maxValue, t);
					_value = Math.max(_minValue,t);
					_scrollTarget.VValue = _value;
				}
			}else {
				if(_wheelType=="both" || _wheelType=="h"){
					_value = Math.min(_maxValue, t);
					_value = Math.max(_minValue,t);
					_scrollTarget.HValue = _value;
				}
			}
			updatauiCondition();
		}
		//down up event
		private function pressUPBT(ev:MouseEvent) {
			_startPressScrollButtonTime = getTimer();
			_upBT.addEventListener(Event.ENTER_FRAME, upbuttonFun);
			if(stage!=null){
				stage.addEventListener(MouseEvent.MOUSE_UP, upUPBT);
			}
		}
		private function upUPBT(ev:MouseEvent) {
			_upBT.removeEventListener(Event.ENTER_FRAME, upbuttonFun);
			if(stage!=null){
				stage.removeEventListener(MouseEvent.MOUSE_UP, upUPBT);
			}
		}
		private function upbuttonFun(ev:Event) {
			var b:uint = uint((getTimer() - _startPressScrollButtonTime) / _ScrollSpeedUpPS)+1;
			var v:Number = _value - _step * b;
			
			_value = Math.max(_minValue,v);
			
			if(_VorH){
				_scrollTarget.VValue = _value;
			}else {
				_scrollTarget.HValue = _value;
			}
			updatauiCondition();
		}
		//down button event
		private function pressDOWNBT(ev:MouseEvent) {
			_startPressScrollButtonTime = getTimer();
			_downBT.addEventListener(Event.ENTER_FRAME, downbuttonFun);
			if(stage!=null){
				stage.addEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
			}
		}
		private function upDOWNBT(ev:MouseEvent) {
			_downBT.removeEventListener(Event.ENTER_FRAME, downbuttonFun);
			if(stage!=null){
				stage.removeEventListener(MouseEvent.MOUSE_UP, upDOWNBT);
			}
		}
		private function downbuttonFun(ev:Event) {
			var b:uint = uint((getTimer() - _startPressScrollButtonTime) / _ScrollSpeedUpPS)+1;
			var v:Number = _value + _step * b;
			_value = Math.min(_maxValue, v);
			if(_VorH){
				_scrollTarget.VValue = _value;
			}else {
				_scrollTarget.HValue = _value;
			}
			updatauiCondition();
		}
		//hand event
		private function mouseDownFun(ev:MouseEvent) {
			if(_VorH){
				_hand.startDrag(false, new Rectangle(_hand.x, _bar.y, 0, _bar.height - _hand.height));
			}else {
				_hand.startDrag(false, new Rectangle(_bar.x, _hand.y, _bar.width - _hand.width,0));
			}
			_hand.addEventListener(Event.ENTER_FRAME, handEnterFrameFun);
		}
		private function mouseUpFun(ev:MouseEvent) {
			_hand.stopDrag();
			_hand.removeEventListener(Event.ENTER_FRAME, handEnterFrameFun);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpFun);
		}
		private function handEnterFrameFun(ev:Event) {
			if (_bar != null) {
				if (_scrollTarget == null) return;
				var v:Number;
				var rv:Number;
				if (_VorH) {
					v = (_hand.y - _bar.y) / (_bar.height - _hand.height);
					v = fixNumber(v);
					rv = v * (_maxValue - _minValue) + _minValue;
					rv = fixRange(rv, _minValue, _maxValue);
					if (rv != _value && _scrollTarget.VValue!=rv) {
						_scrollTarget.VValue = rv;
						this._value = rv;
					}
				}else {
					v = (_hand.x - _bar.x) / (_bar.width - _hand.width);
					v = fixNumber(v);
					rv = v * (_maxValue - _minValue) + _minValue;
					rv = fixRange(rv, _minValue, _maxValue);
					if (rv != _value) {
						_scrollTarget.HValue = rv;
						this._value = rv;
					}
				}
			}
			
		}
		
		private function fixRange(v:Number, min:Number, max:Number) {
			v = Math.min(max, v);
			v = Math.max(min, v);
			v = fixNumber(v);
			return v;
		}
		private function fixNumber(v:Number, l:Number = 2):Number {
			var ten:uint = Math.pow(10, l);
			v = Math.round(v * ten) / ten;
			return v;
		}
		
		/* INTERFACE Leophy.Interfaces.IControls.IScroll.IScrollUI */
		
		public function onScrollSizeChanged(ev:Event):void
		{
			var obj:IScorllEnable = IScorllEnable(ev.target);
			UpdataUI(obj.HValue, obj.MinScrollH, obj.MaxScrollH, obj.VValue, obj.MinScrollV, obj.MaxScrollV);
		}
	}
	
}